-module(gen_socket_server).

-behaviour(gen_server).

-define(TCP_OPTIONS, [binary, {packet, raw}, {active, false}, {reuseaddr, true}]).
-record(server_state, {
			port,			% listen port
			loop,			% the logic fun
			ip=any,			% ip
			lsocket=null
%%			,		% listen socket
%%			conn=0,			% curent connect
%%			maxconn			% max connect
			}).

%% API
-export([start/3]).
-export([accept_loop/3]).

%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
         terminate/2, code_change/3]).

-record(state, {}).

%%====================================================================
%% API
%%====================================================================
%%--------------------------------------------------------------------
%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
%% Description: Starts the server
%%--------------------------------------------------------------------
%% start the generic server
start(Name, Port,  Loop) ->
	State = #server_state{port=Port, loop=Loop},
	gen_server:start_link({local, Name}, ?MODULE, State, []).
	


%%====================================================================
%% gen_server callbacks
%%====================================================================

%%--------------------------------------------------------------------
%% Function: init(Args) -> {ok, State} |
%%                         {ok, State, Timeout} |
%%                         ignore               |
%%                         {stop, Reason}
%% Description: Initiates the server
%%--------------------------------------------------------------------
%% create listen socket
init(State = #server_state{port=Port}) ->
	case gen_tcp:listen(Port, ?TCP_OPTIONS) of
		{ok, LSocket} ->
			{ok, accept(State#server_state{lsocket=LSocket})};
		{error, Reason} ->
			{stop, {create_listen_socket, Reason}}
	end.

%% accept spawn a new process
accept(State =#server_state{lsocket=LSocket, loop=Loop}) ->
	proc_lib:spawn(gen_socket_server, accept_loop, [self(), LSocket, Loop]),
	State.


%% accept the new connection
accept_loop(Server, LSocket, {M, F}=Loop) ->
	{ok, Sock} = gen_tcp:accept(LSocket),
        error_logger:info_msg("gen_socket_server:accept a new connect~p~n",[Sock]),
        proc_lib:spawn(gen_socket_server, accept_loop, [self(), LSocket, Loop]),
        M:F(Sock),
	gen_tcp:close(Sock).



%%--------------------------------------------------------------------
%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
%%                                      {reply, Reply, State, Timeout} |
%%                                      {noreply, State} |
%%                                      {noreply, State, Timeout} |
%%                                      {stop, Reason, Reply, State} |
%%                                      {stop, Reason, State}
%% Description: Handling call messages
%%--------------------------------------------------------------------
handle_call(_Request, _From, State) ->
    Reply = ok,
    {reply, Reply, State}.

%%--------------------------------------------------------------------
%% Function: handle_cast(Msg, State) -> {noreply, State} |
%%                                      {noreply, State, Timeout} |
%%                                      {stop, Reason, State}
%% Description: Handling cast messages
%%--------------------------------------------------------------------
handle_cast(_Msg, State) ->
    {noreply, State}.

%%--------------------------------------------------------------------
%% Function: handle_info(Info, State) -> {noreply, State} |
%%                                       {noreply, State, Timeout} |
%%                                       {stop, Reason, State}
%% Description: Handling all non call/cast messages
%%--------------------------------------------------------------------
handle_info(_Info, State) ->
    {noreply, State}.

%%--------------------------------------------------------------------
%% Function: terminate(Reason, State) -> void()
%% Description: This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any necessary
%% cleaning up. When it returns, the gen_server terminates with Reason.
%% The return value is ignored.
%%--------------------------------------------------------------------
terminate(_Reason, _State) ->
    ok.

%%--------------------------------------------------------------------
%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
%% Description: Convert process state when code is changed
%%--------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------

